Tidy Finance Webinar Series
Harry Markowitz pioneered modern portfolio theory
How to optimally allocate wealth across assets with different characteristics, e.g. returns, risks, and correlations?
Expected return
Example: expect a 10% return from Apple over next 12 months
Risk
Example: Apple’s stock might move \(\pm15\)% over next year
Markowitz: correlations across assets also matter!
Fruit basket analogy
Diversification in investment
Sum annual returns and divide by number of periods:
Example:
Assumption: past performance is indicative of future
# A tibble: 37,710 × 3
symbol date price
<chr> <date> <dbl>
1 UNH 2019-08-01 231.
2 UNH 2019-08-02 232.
3 UNH 2019-08-05 227.
4 UNH 2019-08-06 230.
5 UNH 2019-08-07 229.
6 UNH 2019-08-08 230.
7 UNH 2019-08-09 231.
8 UNH 2019-08-12 226.
9 UNH 2019-08-13 231.
10 UNH 2019-08-14 226.
# ℹ 37,700 more rows
# A tibble: 37,680 × 3
symbol date ret
<chr> <date> <dbl>
1 AAPL 2019-08-02 -0.0212
2 AAPL 2019-08-05 -0.0523
3 AAPL 2019-08-06 0.0189
4 AAPL 2019-08-07 0.0104
5 AAPL 2019-08-08 0.0221
6 AAPL 2019-08-09 -0.00824
7 AAPL 2019-08-12 -0.00254
8 AAPL 2019-08-13 0.0423
9 AAPL 2019-08-14 -0.0298
10 AAPL 2019-08-15 -0.00498
# ℹ 37,670 more rows
assets <- returns_daily |>
group_by(symbol) |>
summarize(mu = mean(ret))
fig_mu <- assets |>
ggplot(aes(x = mu, y = fct_reorder(symbol, mu),
fill = mu > 0)) +
geom_col() +
scale_x_continuous(labels = scales::percent) +
labs(x = NULL, y = NULL, fill = NULL,
title = "Average daily returns of DOW index constituents")\(\text{Expected Portfolio Return} = \sum_{i=1}^n \omega_i \hat{\mu}_i\)
Example:
Assumption: portfolio weights are constant over time
\[\hat{\sigma}_i = \sqrt{\frac{1}{T-1} \sum_{t=1}^{T} (R_{it} - \hat{\mu}_i)^2}\]
Interpretation: higher volatility indicates higher risk
volatilities <- returns_daily |>
group_by(symbol) |>
summarize(sigma = sd(ret))
assets <- assets |>
left_join(volatilities, join_by(symbol))
fig_sigma <- assets |>
ggplot(aes(x = sigma, y = fct_reorder(symbol, sigma))) +
geom_col() +
scale_x_continuous(labels = scales::percent) +
labs(x = NULL, y = NULL,
title = "Daily volatilities of DOW index constituents")\[\hat{\sigma}_{ij} = \frac{1}{T-1} \sum_{t=1}^{T} (R_{it} - \hat{\mu}_i)(R_{jt} - \hat{\mu}_j)\]
Interpretation:
returns_wide <- returns_daily |>
pivot_wider(names_from = symbol, values_from = ret)
sigma <- returns_wide |>
select(-date) |>
cov()
fig_sigma <- sigma |>
as_tibble(rownames = "symbol_a") |>
pivot_longer(-symbol_a, names_to = "symbol_b") |>
ggplot(aes(x = symbol_a, y = fct_rev(symbol_b),
fill = value)) +
geom_tile() +
scale_fill_gradient(low = "blue", high = "red") +
labs(x = NULL, y = NULL, fill = "(Co-)Variance",
title = "Variance-covariance matrix of Dow Industrial Average constituents") Portfolio variance is calculated as
\[\sum_{i=1}^{n} \sum_{j=1}^{n} \omega_i \omega_j \hat{\sigma}_{ij}\]
Minimize portfolio variance
\[\min_{\omega_1, ... \omega_n} \sum_{i=1}^{n} \sum_{j=1}^{n} \omega_i \omega_j \hat{\sigma}_{ij}\]
while staying fully invested
\[\sum_{i=1}^{n} \omega_i = 1\]
Minimize portfolio variance
\[\min_{\omega} \omega' \hat{\Sigma} \omega\]
while staying fully invested
\[ \omega'\iota = 1\]
\[\omega_\text{mvp} = \frac{\Sigma^{-1}\iota}{\iota'\Sigma^{-1}\iota}\]
Minimize portfolio variance
\[\min_{\omega} \omega' \hat{\Sigma} \omega\]
While earning minimum expected return \(\bar{\mu}\)
Achieve at least average Nasdaq 100 return:
Note: \(\bar\mu\) needs to be higher than \(\hat\mu_{mvp}\)
\[\omega_{efp} = \frac{\lambda^*}{2}\left(\Sigma^{-1}\mu -\frac{D}{C}\Sigma^{-1}\iota \right)\]
where \(\lambda^* = 2\frac{\bar\mu - D/C}{E-D^2/C}\), \(C = \iota'\Sigma^{-1}\iota\), \(D=\iota'\Sigma^{-1}\mu\), and \(E=\mu'\Sigma^{-1}\mu\)
See details on tidy-finance.org
C <- as.numeric(t(iota) %*% sigma_inv %*% iota)
D <- as.numeric(t(iota) %*% sigma_inv %*% mu)
E <- as.numeric(t(mu) %*% sigma_inv %*% mu)
lambda_tilde <- as.numeric(2 * (mu_bar - D / C) / (E - D^2 / C))
omega_efp <- as.vector(omega_mvp + lambda_tilde / 2 * (sigma_inv %*% mu - D * omega_mvp))
summary_efp <- tibble(
mu = sum(omega_efp * mu),
sigma = as.numeric(sqrt(t(omega_efp) %*% sigma %*% omega_efp)),
type = "Efficient Portfolio"
)summaries <- bind_rows(
assets, summary_mvp, summary_efp
)
fig_summaries <- summaries |>
ggplot(aes(x = sigma, y = mu)) +
geom_point(data = summaries |> filter(is.na(type))) +
geom_point(data = summaries |> filter(!is.na(type)), color = "red", size = 3) +
ggrepel::geom_label_repel(aes(label = type)) +
scale_x_continuous(labels = scales::percent) +
scale_y_continuous(labels = scales::percent) +
labs(x = "Volatility", y = "Average return",
title = "Efficient and minimum-variance portfolios for DOW index constituents",
subtitle = "Points correspond to individual assets") Mutual fund separation theorem: any linear combination of efficient portfolios, is also efficient
\[\omega_{eff} = a \cdot \omega_{efp} + (1-a) \cdot\omega_{mvp}\]
Highest achievable expected return at each level of risk
summaries <- bind_rows(
summaries, efficient_frontier
)
fig_efficient_frontier <- summaries |>
ggplot(aes(x = sigma, y = mu)) +
geom_point(data = summaries |> filter(is.na(type))) +
geom_point(data = summaries |> filter(!is.na(type)), color = "red", size = 3) +
ggrepel::geom_label_repel(aes(label = type)) +
scale_x_continuous(labels = scales::percent) +
scale_y_continuous(labels = scales::percent) +
labs(x = "Volatility", y = "Average return",
title = "Efficient frontier for DOW index constituents",
subtitle = "Points correspond to individual assets") library(PortfolioAnalytics)
library(CVXR)
returns_matrix <- column_to_rownames(returns_wide, var = "date")
problem_mvp <- portfolio.spec(colnames(returns_matrix)) |>
add.objective(type = "risk", name = "var") |>
add.constraint("full_investment")
solution_mvp <- optimize.portfolio(
returns_matrix, problem_mvp, optimize_method = "CVXR"
)
all.equal(omega_mvp, as.vector(solution_mvp$weights))[1] TRUE
Short sale constraints: add.constraint("long_only")
Position limit: add.constraint("position_limit", max_pos = 10)
Expected shortfall: add.objective(type = "risk", name = "ES")
.. and many more, see official PortfolioAnalytics vignette
tidyfinance packagePortfolioAnalyticsFollow on LinkedIn for news: christophscheuch
Slides on: talks.tidy-finance.org